﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using HiCore.Extensions.UnitOfWork.EntityFramework.Domain;
using HiCore.Extensions.DependencyInjection;
using HiCore.Extensions.UnitOfWork.EntityFramework;

namespace HiCore.WebApi.Example.DbContexts.Interceptors
{
    public class DomainEventInterceptor : SaveChangesInterceptor
    {
        private readonly DomainEventDispatcher _domainEventDispatcher;

        public DomainEventInterceptor(IServiceProvider serviceProvider)
        {
            _domainEventDispatcher = serviceProvider.GetRequiredService<DomainEventDispatcher>();
        }

        public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = default)
        {
            int excutedCount = await base.SavedChangesAsync(eventData, result, cancellationToken);

            if (excutedCount > 0)
            {
                await DispatchEvents(eventData.Context.ChangeTracker);
            }
            return excutedCount;
        }

        private Task DispatchEvents(ChangeTracker changeTracker)
        {
            var domainEventEntities = changeTracker?.Entries<AggregateRoot>()?.Where(w => w.Entity.DomainEvents != null).Select(x => x.Entity.DomainEvents)?.SelectMany(x => x);

            if (domainEventEntities != null && domainEventEntities.Any())
            {
                foreach (var domainEventEntity in domainEventEntities)
                {
                    _domainEventDispatcher.Handler.Invoke(domainEventEntity);
                }
            }
            return Task.CompletedTask;
        }
    }
}
